package com.thinvent.smart.chain.util;

import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.asn1.sec.ECPrivateKey;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.openssl.*;
import org.bouncycastle.openssl.jcajce.*;
import org.bouncycastle.operator.OutputEncryptor;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;

import java.io.*;
import java.security.*;

/**
 *
 */
public class CryptUtils {

    static{
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     *
     * @param privateKey
     * @param password
     * @param outputStream
     * @throws Exception
     */
    public static void writePkcs1(PrivateKey privateKey, String password, OutputStream outputStream) throws Exception {
        PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream));
        final PEMEncryptor pemEncryptor = new JcePEMEncryptorBuilder("AES-256-CBC").build(password.toCharArray());
        JcaMiscPEMGenerator gen = new JcaMiscPEMGenerator(privateKey, pemEncryptor);
        PemObject obj = gen.generate();
        pemWriter.writeObject(obj);
        pemWriter.close();
    }

    /**
     *
     * @param privateKey
     * @param password
     * @param outputStream
     * @throws Exception
     */
    public static void writePkcs8(PrivateKey privateKey, String password, OutputStream outputStream) throws Exception {
        PemWriter pemWriter = new PemWriter(new OutputStreamWriter(outputStream));
        JceOpenSSLPKCS8EncryptorBuilder encryptorBuilder = new JceOpenSSLPKCS8EncryptorBuilder(
                PKCS8Generator.PBE_SHA1_3DES);
        encryptorBuilder.setRandom(new SecureRandom());
        encryptorBuilder.setPasssword(password.toCharArray());
        OutputEncryptor oe = encryptorBuilder.build();
        JcaPKCS8Generator gen = new JcaPKCS8Generator(privateKey, oe);
        pemWriter.writeObject(gen.generate());
        pemWriter.close();
    }

    /**
     * 国密
     * @param password
     * @param isPkcs8
     * @param outputStream
     * @return
     * @throws Exception
     */
    public static KeyPair generateEncryptedSmPrivateKey(String password, Boolean isPkcs8, OutputStream outputStream)
            throws Exception {
        ECNamedCurveParameterSpec ecNamedCurveParameterSpec = ECNamedCurveTable.getParameterSpec("sm2p256v1");
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC");
        keyPairGenerator.initialize(ecNamedCurveParameterSpec, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        if (!isPkcs8) {
            writePkcs1(keyPair.getPrivate(), password, outputStream);
        } else {
            writePkcs8(keyPair.getPrivate(), password, outputStream);
        }
        return keyPair;
    }

    /**
     * 普通合约链
     * @param password
     * @param isPkcs8
     * @param outputStream
     * @return
     * @throws Exception
     */
    public static KeyPair generateEncryptedEcck1PrivateKey(String password, Boolean isPkcs8, OutputStream outputStream)
            throws Exception {
        ECNamedCurveParameterSpec ecParameterSpec = ECNamedCurveTable.getParameterSpec("secp256k1");
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "BC");
        keyPairGenerator.initialize(ecParameterSpec, new SecureRandom());
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        if (!isPkcs8) {
            writePkcs1(keyPair.getPrivate(), password, outputStream);
        } else {
            writePkcs8(keyPair.getPrivate(), password, outputStream);
        }
        return keyPair;
    }
    /**
     * 获取公钥
     * @param keyPair
     * @return
     * @throws Exception
     */
    public static String getPublicKeyString(KeyPair keyPair) throws Exception {
        ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(
                PrivateKeyInfo.getInstance(keyPair.getPrivate().getEncoded()).parsePrivateKey());
        byte[] originalBytes = ecPrivateKey.getPublicKey().getBytes();
        byte[] transform = new byte[originalBytes.length - 1];
        System.arraycopy(originalBytes, 1, transform, 0, transform.length);
        return Hex.toHexString(transform);
    }
}
